package com.fwmagic.dynamic_rule.service.impl;

import com.fwmagic.dynamic_rule.bean.LogBean;
import com.fwmagic.dynamic_rule.bean.RuleAtomicParam;
import com.fwmagic.dynamic_rule.bean.RuleParam;
import com.fwmagic.dynamic_rule.service.UserActionSequenceQueryService;
import com.fwmagic.dynamic_rule.utils.RuleCalcUtils;
import com.fwmagic.dynamic_rule.utils.SystemPrintUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.flink.api.common.state.ListState;

import java.util.ArrayList;
import java.util.List;

/**
 * A(p1=v2,p3=v4) -> B(p5=v6) -> C()
 * 用户行为次序类条件查询服务实现(在Flink的State中查询)
 */
@Slf4j
public class UserActionSequenceQueryServiceStateImpl implements UserActionSequenceQueryService {

    private ListState<LogBean> listState;

    public UserActionSequenceQueryServiceStateImpl(ListState<LogBean> listState) {
        this.listState = listState;
    }

    public UserActionSequenceQueryServiceStateImpl() {
    }

    /**
     * 判断用户行为次序条件和定义的规则是否匹配
     *
     * @param ruleParam
     * @return
     * @throws Exception
     */
    @Override
    public boolean queryActionSequence(String deviceId, RuleParam ruleParam) throws Exception {
        //获取所有的历史事件数据
        Iterable<LogBean> logBeans = listState.get();

        //获取规则中的次序条件
        List<RuleAtomicParam> userActionSequenceParam = ruleParam.getUserActionSequenceParam();

        //获取匹配的最大次序的步数
        int maxStep = queryActionSequenceHelperV2(logBeans, userActionSequenceParam);

//        log.info("规则:{},用户:{},近期查询State , 步骤匹配计算完成情况：查询到的Step:{}, 条件中Step：{}", ruleParam.getRuleId(), deviceId, ruleParam.getUserActionSequenceQueriedMaxStep(), userActionSequenceParam.size());

        //设置实际匹配到的最大次序的步数
        ruleParam.setUserActionSequenceQueriedMaxStep(ruleParam.getUserActionSequenceQueriedMaxStep() + maxStep);

        return ruleParam.getUserActionSequenceQueriedMaxStep() == userActionSequenceParam.size();
    }

    /**
     * 事件匹配规则，返回最大步长
     *
     * @param logBeans
     * @param userActionSequenceParam
     * @return
     */
    public int queryActionSequenceHelperV2(Iterable<LogBean> logBeans, List<RuleAtomicParam> userActionSequenceParam) {
        int maxStep = 0;
        for (LogBean logBean : logBeans) {
            if (RuleCalcUtils.eventBeanParamMatchRuleParam(logBean, userActionSequenceParam.get(maxStep), true)) {
                maxStep++;
            }
            if (maxStep == userActionSequenceParam.size()) break;
        }
        return maxStep;
    }

    /**
     * 事件匹配规则，返回最大步长
     *
     * @param logBeans
     * @param userActionSequenceParam
     * @return
     */
    public int queryActionSequenceHelperV1(Iterable<LogBean> logBeans, List<RuleAtomicParam> userActionSequenceParam) {
        ArrayList<LogBean> events = new ArrayList<>();
        CollectionUtils.addAll(events, logBeans.iterator());

        int maxStep = 0;
        //定义索引，后续事件需要匹配后将其更新
        int index = 0;
        for (RuleAtomicParam ruleAtomicParam : userActionSequenceParam) {
            //标记本次是否匹配到规则
            boolean isFind = false;
            for (int i = index; i < events.size(); i++) {
                LogBean logBean = events.get(i);
                boolean isMatch = RuleCalcUtils.eventBeanParamMatchRuleParam(logBean, ruleAtomicParam, false);
                //匹配到步骤
                if (isMatch) {
                    //步长加1
                    maxStep++;
                    //更新循环索引
                    index = i + 1;
                    isFind = true;
                    //跳出内循环
                    break;
                }
            }
            //有任何一个步骤未匹配，则跳出外循环
            if (!isFind) {
                break;
            }
        }
        return maxStep;
    }

}
